home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / tcpsubr.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  6KB  |  309 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7.  
  8. struct tcb *tcbs[NTCB];
  9. int16 tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  10. int32 tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  11.  
  12. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  13. struct tcb *
  14. lookup_tcb(conn)
  15. struct connection *conn;
  16. {
  17.     register struct tcb *tcb;
  18.     int16 hash_tcb();    
  19.  
  20.     tcb = tcbs[hash_tcb(conn)];
  21.     while(tcb != NULLTCB){
  22.         /* Yet another structure compatibility hack */
  23.         if(conn->local.address == tcb->conn.local.address
  24.          && conn->remote.address == tcb->conn.remote.address
  25.          && conn->local.port == tcb->conn.local.port
  26.          && conn->remote.port == tcb->conn.remote.port)
  27.             break;
  28.         tcb = tcb->next;
  29.     }
  30.     return tcb;
  31. }
  32.  
  33. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  34. struct tcb *
  35. create_tcb(conn)
  36. struct connection *conn;
  37. {
  38.     register struct tcb *tcb;
  39.     void tcp_timeout(),tcp_msl();
  40.     void link_tcb();
  41.  
  42.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  43.         return tcb;
  44.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  45.         return NULLTCB;
  46.     ASSIGN(tcb->conn,*conn);
  47.  
  48.     tcb->cwind = tcb->mss = tcp_mss;
  49.     tcb->ssthresh = 65535;
  50.     tcb->srtt = tcp_irtt;
  51.     /* Initialize timer intervals */
  52.     tcb->timer.start = tcb->srtt / MSPTICK;
  53.     tcb->timer.func = tcp_timeout;
  54.     tcb->timer.arg = (char *)tcb;
  55.     tcb->rtt_timer.start = MAX_TIME; /* Largest possible value */
  56.  
  57.     link_tcb(tcb);
  58.     return tcb;
  59. }
  60.  
  61. /* Close our TCB */
  62. void
  63. close_self(tcb,reason)
  64. register struct tcb *tcb;
  65. char reason;
  66. {
  67.     struct reseq *rp,*rp1;
  68.  
  69.     stop_timer(&tcb->timer);
  70.     stop_timer(&tcb->rtt_timer);
  71.     tcb->reason = reason;
  72.  
  73.     /* Flush reassembly queue; nothing more can arrive */
  74.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  75.         rp1 = rp->next;
  76.         free_p(rp->bp);
  77.         free((char *)rp);
  78.     }
  79.     tcb->reseq = NULLRESEQ;
  80.     setstate(tcb,CLOSED);
  81. }
  82.  
  83. /* Determine initial sequence number */
  84. int32
  85. iss()
  86. {
  87.     static int32 seq;
  88.  
  89.     seq += 250000;
  90.     return seq;
  91. }
  92.  
  93. /* Sequence number comparisons
  94.  * Return true if x is between low and high inclusive,
  95.  * false otherwise
  96.  */
  97. int
  98. seq_within(x,low,high)
  99. register int32 x,low,high;
  100. {
  101.     if(low <= high){
  102.         if(low <= x && x <= high)
  103.             return 1;
  104.     } else {
  105.         if(low >= x && x >= high)
  106.             return 1;
  107.     }
  108.     return 0;
  109. }
  110. int
  111. seq_lt(x,y)
  112. register int32 x,y;
  113. {
  114.     return (long)(x-y) < 0;
  115. }
  116. int
  117. seq_le(x,y)
  118. register int32 x,y;
  119. {
  120.     return (long)(x-y) <= 0;
  121. }
  122. int
  123. seq_gt(x,y)
  124. register int32 x,y;
  125. {
  126.     return (long)(x-y) > 0;
  127. }
  128. int
  129. seq_ge(x,y)
  130. register int32 x,y;
  131. {
  132.     return (long)(x-y) >= 0;
  133. }
  134.  
  135. /* Hash a connect structure into the hash chain header array */
  136. static int16
  137. hash_tcb(conn)
  138. struct connection *conn;
  139. {
  140.     register int16 hval;
  141.  
  142.     /* Compute hash function on connection structure */
  143.     hval = hiword(conn->remote.address);
  144.     hval ^= loword(conn->remote.address);
  145.     hval ^= hiword(conn->local.address);
  146.     hval ^= loword(conn->local.address);
  147.     hval ^= conn->remote.port;
  148.     hval ^= conn->local.port;
  149.     hval %= NTCB;
  150.     return hval;
  151. }
  152. /* Insert TCB at head of proper hash chain */
  153. void
  154. link_tcb(tcb)
  155. register struct tcb *tcb;
  156. {
  157.     register struct tcb **tcbhead;
  158.     int16 hash_tcb();
  159.     char i_state;
  160.  
  161.     tcb->prev = NULLTCB;
  162.     i_state = disable();
  163.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  164.     tcb->next = *tcbhead;
  165.     if(tcb->next != NULLTCB){
  166.         tcb->next->prev = tcb;
  167.     }
  168.     *tcbhead = tcb;
  169.     restore(i_state);
  170. }
  171. /* Remove TCB from whatever hash chain it may be on */
  172. void
  173. unlink_tcb(tcb)
  174. register struct tcb *tcb;
  175. {
  176.     register struct tcb **tcbhead;
  177.     int16 hash_tcb();
  178.     char i_state;
  179.  
  180.     i_state = disable();
  181.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  182.     if(*tcbhead == tcb)
  183.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  184.     if(tcb->prev != NULLTCB)
  185.         tcb->prev->next = tcb->next;
  186.     if(tcb->next != NULLTCB)
  187.         tcb->next->prev = tcb->prev;
  188.     restore(i_state);
  189. }
  190. void
  191. setstate(tcb,newstate)
  192. register struct tcb *tcb;
  193. register char newstate;
  194. {
  195.     register char oldstate;
  196.  
  197.     oldstate = tcb->state;
  198.     tcb->state = newstate;
  199.     if(tcb->s_upcall){
  200.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  201.     }
  202.     /* Notify the user that he can begin sending data */
  203.     if(tcb->t_upcall && newstate == ESTABLISHED){
  204.         (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  205.     }
  206. }
  207. /* Convert TCP header in host format into mbuf ready for transmission,
  208.  * link in data (if any), and compute checksum
  209.  */
  210. struct mbuf *
  211. htontcp(tcph,data,ph)
  212. struct tcp *tcph;
  213. struct mbuf *data;
  214. struct pseudo_header *ph;
  215. {
  216.     int16 hdrlen;
  217.     struct mbuf *bp;
  218.     register char *cp;
  219.     int16 csum;
  220.  
  221.     hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  222.     
  223.     if((bp = pushdown(data,hdrlen)) == NULLBUF){
  224.         free_p(data);
  225.         return NULLBUF;
  226.     }
  227.     cp = bp->data;
  228.     cp = put16(cp,tcph->source);
  229.     cp = put16(cp,tcph->dest);
  230.     cp = put32(cp,tcph->seq);
  231.     cp = put32(cp,tcph->ack);
  232.     *cp++ = hdrlen << 2;    /* Offset field */
  233.     *cp++ = tcph->flags;
  234.     cp = put16(cp,tcph->wnd);
  235.     *cp++ = 0;    /* Zero out checksum field */
  236.     *cp++ = 0;
  237.     cp = put16(cp,tcph->up);
  238.  
  239.     if(tcph->mss != 0){
  240.         *cp++ = MSS_KIND;
  241.         *cp++ = MSS_LENGTH;
  242.         cp = put16(cp,tcph->mss);
  243.     }
  244.     csum = cksum(ph,bp,ph->length);
  245.     cp = &bp->data[16];    /* Checksum field */    
  246.     *cp++ = csum >> 8;
  247.     *cp = csum;
  248.  
  249.     return bp;
  250. }
  251. /* Pull TCP header off mbuf */
  252. int
  253. ntohtcp(tcph,bpp)
  254. struct tcp *tcph;
  255. struct mbuf **bpp;
  256. {
  257.     int16 hdrlen;
  258.     int16 i,optlen;
  259.  
  260.     tcph->source = pull16(bpp);
  261.     tcph->dest = pull16(bpp);
  262.     tcph->seq = pull32(bpp);
  263.     tcph->ack = pull32(bpp);
  264.     if(*bpp == NULLBUF)
  265.         /* Buffer too short to pull off header length */
  266.         return -1;
  267.     hdrlen = (pullchar(bpp) & 0xf0) >> 2;
  268.     tcph->flags = pullchar(bpp);
  269.     tcph->wnd = pull16(bpp);
  270.     (void)pull16(bpp);    /* Skip checksum */
  271.     tcph->up = pull16(bpp);
  272.     tcph->mss = 0;
  273.  
  274.     /* Check for option field. Only space for one is allowed, but
  275.      * since there's only one TCP option (MSS) this isn't a problem
  276.      */
  277.     if(hdrlen < TCPLEN)
  278.         return -1;    /* Header smaller than legal minimum */
  279.     if(hdrlen == TCPLEN)
  280.         return hdrlen;    /* No options, all done */
  281.  
  282.     if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  283.         /* Remainder too short for options length specified */
  284.         return -1;
  285.     }
  286.     /* Process options */
  287.     for(i=TCPLEN; i < hdrlen;){
  288.         switch(pullchar(bpp)){
  289.         case EOL_KIND:
  290.             i++;
  291.             goto eol;    /* End of options list */
  292.         case NOOP_KIND:
  293.             i++;
  294.             break;
  295.         case MSS_KIND:
  296.             optlen = pullchar(bpp);
  297.             if(optlen == MSS_LENGTH)
  298.                 tcph->mss = pull16(bpp);
  299.             i += optlen;
  300.             break;
  301.         }
  302.     }
  303. eol:
  304.     /* Get rid of any padding */
  305.     if(i < hdrlen)
  306.         pullup(bpp,NULLCHAR,hdrlen - i);
  307.     return hdrlen;
  308. }
  309.